/**
 * Redo the program in Figure 15.33 using the POSIX semaphore functions from Section 15.10
 * to alternate between the parent and the child.
 **/
#include "apue.h"

#include <fcntl.h>
#include <semaphore.h>
#include <sys/mman.h>

#define NLOOPS 1000
#define SIZE sizeof(long) /* size of shared memory area */

static int update(long *ptr)
{
  return ((*ptr)++); /* return value before increment */
}

int main(void)
{
  int fd, i, counter;
  pid_t pid;
  void *area;
  sem_t *sem1, *sem2;

  const char *name1 = "/sem1";
  const char *name2 = "/sem2";

  if ((fd = open("/dev/zero", O_RDWR)) < 0)
    err_sys("open error");
  if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
    err_sys("mmap error");
  close(fd); /* can close /dev/zero now that it's mapped */

  sem1 = sem_open(name1, O_CREAT, FILE_MODE, 0); /* 父进程使用 */
  sem2 = sem_open(name2, O_CREAT, FILE_MODE, 0); /* 子进程使用 */

  if ((pid = fork()) < 0) {
    err_sys("fork error");
  } else if (pid > 0) { /* parent */
    for (i = 0; i < NLOOPS; i += 2) {
      if ((counter = update((long *)area)) != i)
        err_quit("parent: expected %d, got %d", i, counter);
      else
        printf("parent: %d\n", i);

      //   TELL_CHILD(pid);
      sem_post(sem2);
      //   WAIT_CHILD();
      sem_wait(sem1);
    }
  } else { /* child */
    sem1 = sem_open(name1, 0);
    sem2 = sem_open(name2, 0);
    for (i = 1; i < NLOOPS + 1; i += 2) {
      //   WAIT_PARENT();
      sem_wait(sem2);

      if ((counter = update((long *)area)) != i)
        err_quit("child: expected %d, got %d", i, counter);
      else
        printf("child : %d\n", i);

      //   TELL_PARENT(getppid());
      sem_post(sem1);
    }
  }

  exit(0);
}
